package hotciv.view;

import hotciv.framework.*;
import hotciv.standard.GameConstants;

import java.awt.*;
import javax.swing.*;
import java.awt.event.*;

/** StatusFrame is a JFrame that displays status for selected units and cities
 * and allow modifying properties on a city. Use the 'display' method
 * to indicate the position in the game world whose unit/city should
 * be displayed.
 *
 * Note: This abstraction is currently highly coupled to the
 * original types of units and workforce focus defined in the HotCiv
 * exercise.
<#if type == "code">

<#include "/data/author.txt">
</#if>
*/

public class StatusFrame extends JFrame {
  private Game game;
  
  /** construct a status frame that displays information
   * for units or cities (or both). 
   * @param title the title to put on the frame.
   * @param game the game to display information about
   */
  public StatusFrame(String title, Game game) {
    super(title);
    this.game = game;
    
    Container pane = getContentPane();
    pane.setLayout( new BoxLayout( pane, BoxLayout.Y_AXIS));
    
    comboListener = new ComboBoxListener();
    
    pane.add( makePlayerPanel() );
    pane.add( new JSeparator() );
    pane.add( makeUnitPanel() );
    pane.add( new JSeparator() );
    pane.add( makeCityPanel() );
    pane.add( new JSeparator() );
    JButton b = new JButton("End of turn");
    b.addActionListener(
        new ActionListener() {
          public void actionPerformed(ActionEvent e){
            StatusFrame.this.game.endOfTurn();
          }
        });
    pane.add(b);
    pack();
  }

  /** display the status of the city/unit at position
   * p in the game.
   * @param p the position to display information about
   */
  public void displayStatusForPosition(Position p) {
    comboListener.setTheCityToChange(p);
    displayUnit( p );
    displayCity( p );
    displayPlayer();
  }
  
  private JLabel unitType, unitOwner, unitMoves;
  private JLabel cityType, cityOwner;
  private JLabel inTurn;

  private void displayPlayer() {
    inTurn.setText(""+game.getPlayerInTurn());
  }
  
  private void displayUnit(Position p) {
    Unit unit = game.getUnitAt(p);
    if ( unit != null ){
      unitType.setText( unit.getTypeString() );
      unitOwner.setText( ""+unit.getOwner() );  
      unitMoves.setText( ""+unit.getMoveCount() );
    } else {
      unitType.setText("-");
      unitOwner.setText("-");
      unitMoves.setText( "-" );
    }
  }
  
  private void displayCity(Position p) {
    City city = game.getCityAt(p);
    if ( city != null ) {
      cityType.setText( ""+p );
      cityOwner.setText( ""+ city.getOwner());
    } else {
      cityType.setText("-");
      cityOwner.setText("-");
    }
  }

  private JPanel makePlayerPanel() {
    JPanel pane = new JPanel();
    pane.setLayout( new GridLayout(0, 2));

    JLabel playerHeadline = new JLabel("Player in turn:");
    inTurn = new JLabel( "-");
    
    pane.add(playerHeadline);
    pane.add(inTurn);
        
    return pane;
  }
  
  private JPanel makeUnitPanel() {
    JPanel pane = new JPanel();
    pane.setLayout( new GridLayout(0, 2));

    // Unit section
    JLabel unitHeadline = new JLabel("Unit:");
    unitType = new JLabel( "-");
    
    pane.add(unitHeadline);
    pane.add(unitType);

    // Unit owner
    JLabel ownerHeadline = new JLabel("Owner:");
    unitOwner = new JLabel( "-");
    
    pane.add(ownerHeadline);
    pane.add(unitOwner);

    // Unit owner
    JLabel moveHeadline = new JLabel("Moves:");
    unitMoves = new JLabel( "-");
    
    pane.add(moveHeadline);
    pane.add(unitMoves);  
    
    return pane;
  }

  private JPanel makeCityPanel() {
    JPanel pane = new JPanel();
    pane.setLayout( new GridLayout(0, 2));

    // Unit section
    JLabel cityHeadline = new JLabel("City:");
    cityType = new JLabel( "(-,-)");
    
    pane.add(cityHeadline);
    pane.add(cityType);
    

    // City owner
    JLabel ownerHeadline = new JLabel("Owner:");
    cityOwner = new JLabel( "-");
    
    pane.add(ownerHeadline);
    pane.add(cityOwner);

    // City production
    JLabel produceHeadline = new JLabel("Produce:");
    String[] unitList = { GameConstants.ARCHER, GameConstants.LEGION };
    JComboBox produce = new JComboBox(unitList);
    produce.addActionListener(comboListener);
    pane.add(produceHeadline);
    pane.add(produce);  

    // City workforce focus
    JLabel focusHeadline = new JLabel("Focus:");
    String[] focusList = { GameConstants.foodFocus, 
                           GameConstants.productionFocus };
    JComboBox focus = new JComboBox( focusList );
    focus.addActionListener( comboListener );
    
    pane.add(focusHeadline);
    pane.add(focus);  
    
    return pane;
  }

  private ComboBoxListener comboListener;
  
  class ComboBoxListener implements ActionListener {
    Position cityPosition = null;
    
    /** set the city that actions on the combo boxes should
     * work on.
     * @param position the position of city to change in 
     * case an combo box event appears. If no city
     * is at position p then nothing happens in case of
     * a combo box event.
     */
    public void setTheCityToChange(Position position) {
      cityPosition = position;
    }
    /** Listens to the combo box. */
    public void actionPerformed(ActionEvent e) {
      JComboBox cb = (JComboBox)e.getSource();
      String selection = (String)cb.getSelectedItem();
      modifyCityState( selection );
    }
    
    /** based upon the combo box string, perform the actual
     * change in the selected city.
     * PreCondition: change should represent a valid string,
     * see GameConstants.
     * @param change the string representing a city production
     * or workforce focus change.
     */
    private void modifyCityState( String change ) {      
      if ( game.getCityAt(cityPosition) == null ) { return; }
      if ( change.equals( GameConstants.foodFocus) || 
          change.equals( GameConstants.productionFocus )) {
        game.changeWorkForceFocusInCityAt(cityPosition, change);
      } else {
        game.changeProductionInCityAt(cityPosition, change);
      }
    }
  }
}

